<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * 多语言系统函数库 类库
 *
 * @author 	FangMinglong
 * @date 	2017-04-13 14:04
 * 
 * @version 1.1.0
 * @date	2017年5月3日 下午2:50:28
 * @desc	重构
 */
class Lib_language
{

	protected $CI;

	public function __construct()
	{
		$this->CI =& get_instance();
		$this->CI->load->config('language', !true);
	}
	
	/**
	 * 是否是支持的语言
	 * 
	 * @date	2017年6月8日 下午12:15:00
	 * 
	 * @param string $language
	 * 
	 * @return boolean
	 */
	public function is_supported_language($language)
	{
		$language_mapper = $this->CI->config->item('supported_languages', 'multi_language');
		
		return array_key_exists($language, $language_mapper);
	}
	
	/**
	 * 从参数中获取合法的语言标识
	 * 
	 * @desc    依次会从第一二个参数中尝试获取合法的语言，否则返回默认语言！
	 * @author  Jason
	 * @date    2017年5月6日 下午3:19:01
	 * 
	 * @version	1.0.1
	 * @desc	提取出 is_supported_language 方法可供 Form_validation 调用
	 * @date	2017年6月8日 下午12:15:00
	 * 
	 * @param   string $language
	 * @param   string $or_default
	 * 
	 * @return  string 支持语言列表中存在的语言标识
	 */
	public function get_supported_language($language, $or_default = 'default')
	{
		if ($this->is_supported_language($language)) {
			return $language;
		}
		if ($this->is_supported_language($or_default)) {
			return $or_default;
		}
		
		$default = $this->CI->config->item('language');
		
		return $default;
	}

	/**
	 * 根据单一资源的[语言表项数据]获取某种[单一]语言的[数据信息关联数组]
	 * 
	 * @param  array  $record   数据库中取出来的语言表项源数据集合，二维数组
	 * @param  string $language 语言标识
	 * 
	 * @return array            数据信息关联数组
	 *         eg: 
	 *         			Array
				        (
				            [fields] => Array
				                (
				                    [101] => abstract
				                    [100] => name
				                    [102] => summary
				                )
				            [values] => Array
				                (
				                    [abstract] => 商户摘要
				                    [name] => 商户名称	
				                    [summary] => 商户简介
				                )
				        )
	 * 
	 * @date   2017年5月3日 下午3:06:39
	 */
	public function get_item_single_language_info($record, $language)
	{
// 		# $record,$language; -> ([fields=>[id=>name],values=>[name=>value])
		$single_info = [];
		foreach ($record as $field_row) {
			if ($field_row['language'] != $language) {
				continue;
			}
		
			$single_info['fields'][$field_row['id']] = $field_row['field_name'];
			$single_info['values'][$field_row['field_name']] = $field_row['field_value'];
		}
		
		return $single_info;
	}

	/**
	 * 根据单一资源的[语言表项数据]获取指定[多种]语言的[数据信息关联数组]
	 * 
	 * @param  array  $resource      数据库中取出来的语言表项源数据集合，二维数组
	 * @param  string $language_list 语言标识列表，如不限制传null
	 * @return array                 数据信息关联数组
	 *         eg:
	 *         			Array
						(
						    [english] => Array
						        (
						            [fields] => Array
						                (
						                    [98] => abstract
						                    [97] => name
						                    [99] => summary
						                )
						            [values] => Array
						                (
						                    [abstract] => Abstract
						                    [name] => Name
						                    [summary] => Summary
						                )
						        )
						    [chinese] => Array
						        (
						            [fields] => Array
						                (
						                    [101] => abstract
						                    [100] => name
						                    [102] => summary
						                )
						            [values] => Array
						                (
						                    [abstract] => 商户摘要
						                    [name] => 商户名称	
						                    [summary] => 商户简介
						                )
						        )
						)
	 * 
	 * @date   2017年5月3日 下午3:12:29
	 */
	public function get_item_multiple_language_info($resource, $language_list = NULL)
	{
// 		# $resource(,$language_list); -> ([language=>[fields=>[id=>name],values=>[name=>value]])
		$metrix = [];
		foreach ($resource as $field_row) {
			$metrix[$field_row['language']]['fields'][$field_row['id']] = $field_row['field_name'];
			$metrix[$field_row['language']]['values'][$field_row['field_name']] = $field_row['field_value'];
		}
		
		$multiple_info = [];
		if (is_array($language_list) && !empty($language_list)) {
			foreach ($language_list as $language) {
				if (!empty($metrix[$language])) {
					$multiple_info[$language] = $metrix[$language];
				}
			}
		} else {
			$multiple_info = $metrix;
		}
		
		return $multiple_info;
	}

	/**
	 * 根据多个资源的[语言表项数据]获取某种[单一]语言的[数据信息关联数组]
	 * 
	 * @param  array  $resource 数据库中取出来的语言表项源数据集合，二维数组
	 * @param  string $language 语言标识
	 * 
	 * @return array            数据信息关联数组
	 * 
	 * @date    2017年5月3日 下午3:23:50
	 * @date	2017年5月12日 下午7:17:09
	 *         		eg: 
	 *         			[id] => Array
				        (
				            [fields] => Array
				                (
				                    [101] => abstract
				                    [100] => name
				                    [102] => summary
				                )
				            [values] => Array
				                (
				                    [abstract] => 商户摘要
				                    [name] => 商户名称	
				                    [summary] => 商户简介
				                )
				        )
	 */
	public function get_list_single_language_info($resources, $language)
	{
// 		# $resources,$language; -> ([resource_id=>[fields=>[id=>name],values=>[name=>value]])
		$single_info = [];
		foreach ($resources as $field_row) {
			if ($field_row['language'] != $language) {
				continue;
			}
			
			$single_info[$field_row['resource']]['fields'][$field_row['id']] = $field_row['field_name'];
			$single_info[$field_row['resource']]['values'][$field_row['field_name']] = $field_row['field_value'];
		}
		
		return $single_info;
	}

	/**
	 * 获取合并过的 一条元素 的数据信息
	 * 
	 * @desc    description
	 * @author  Jason
	 * @date    2017年5月3日 下午1:57:09
	 * 
	 * @param   array 	$item 		一维数组，支持多语言的模型的数据信息，一条
	 * @param   string 	$module 	模型名称
	 * @param   string 	$language 	语言名称
	 * 
	 * @return  array	合并了指定语言后的元素信息
	 */
	public function get_merged_item_data($item, $module, $language)
	{
		$resource = $item['id'];
		
		$this->CI->load->model('mod_language');
		$record = $this->CI->mod_language->select_record($module, $resource, $language);
		
		$language_data = $this->get_item_single_language_info($record, $language);
		
		$merged_data = array_merge($item, @(array) $language_data['values']);
		
		return $merged_data;
	}
	
	/**
	 * 获取合并过的 多条元素 的数据信息
	 *
	 * @desc    description
	 * @author  Jason
	 * @date    2017年5月3日 下午2:17:17
	 *
	 * @param   array 	$item 		二维数组，支持多语言的模型的数据信息，多条
	 * @param   string 	$module 	模型名称
	 * @param   string 	$language 	语言名称
	 *
	 * @return  array	合并了指定语言后的元素信息
	 */
	public function get_merged_list_data($list, $module, $language)
	{
		$merged_data = [];
		foreach ($list as $key => $item) {
			$merged_data[$key] = $this->get_merged_item_data($item, $module, $language);
		}
		
		return $merged_data;
	}
	
	
	/**
	 * 获取合并过的 多条元素 的数据信息，仅包含指定字段
	 *
	 * @desc    与 get_merged_list_data($list, $module, $language) 功能相同，只是仅包含指定字段
	 * @author  Jason
	 * @date    2017年5月15日 上午11:33:36
	 *
	 * @date	2017年5月17日 下午6:04:46
	 * @desc	继【重构，全面支持传递各个函数的全部参数】首个实例
	 * @desc	Fix: where 与 where_in 系列虽然参数表列相同，但首二参数的类型却不同，传参的灵活性也不一致！
	 */
	public function get_merged_list_data_with_fields($list, $module, $language, $field_names)
	{
		$field_names = is_array($field_names) ? $field_names : [$field_names];
		$this->CI->load->model('mod_language');
		$resources = array_column($list, 'id');
		$resources[] = -1;
		$conditions = [
				['select',  	'id, resource, field_name, field_value, language'],
				['where',   	[['module' => $module, 'language' => $language]]],
				#['where_in',	[['resource', $resources]]], 		// Bad!
				#['where_in',	[['field_name', $field_names]]],	// Bad!
				#['where_in',	[['resource' => $resources]]],		// Bad!
				#['where_in',	[['field_name' => $field_names]]],	// Bad!
				['where_in',	['resource', $resources]],
				['where_in',	['field_name', $field_names]],
		];
		$resources = $this->CI->mod_language->select_instances_by_conditions($conditions);
		$language_data = $this->get_list_single_language_info($resources, $language);
// 		#array_walk($language_data, function(&$item) {
// 		#	$item = $item['values'];
// 		#});
		array_walk($list, function(&$item) use ($language_data) {
			if (!empty($language_data[$item['id']]['values'])) {
				$item = array_merge($item, $language_data[$item['id']]['values']);
			}
		});
		
		return $list;
	}
	
	public function get_merged_item_data_with_fields($item, $module, $language, $field_names)
	{
		$list = [$item];
		$list = $this->get_merged_list_data_with_fields($list, $module, $language, $field_names);
		$item = array_pop($list);
		
		return $item;
	}
	
	/**
	 * 根据搜索关键字获取资源ID列表
	 * 
	 * @desc    根据搜索关键字获取资源ID列表。注意：可能为空数组，不能直接用于 WHERE_IN！
	 * @author  Jason
	 * @date    2017年5月18日 下午3:22:44
	 * 
	 * @param string $keyword		关键字
	 * @param string $module		一个模型名，指定搜索的是什么	eg: 'merchant'
	 * @param array  $resources		非语言字段限定条件过滤之后的ID列表。注意：!!不能为空数组!!！
	 * @param string $language		语言标识
	 * @param array  $by_fields		探索的字段列表, 默认为 ['name']
	 * 
	 * @return  array	资源ID列表	eg:	[45, 46, 47]
	 */
	public function get_resources_for_search($keyword, $module, $resources, $language, $by_fields = ['name'])
	{
		$conditions = [
				['select', 'resource'],
				['distinct'],
				['where', [['language' => $language, 'module' => $module]]],
				['where_in', ['field_name', $by_fields]],
				['where_in', ['resource', $resources]],
				['like', ['field_value', $keyword/*, 'before'*/]],
		];
		
		$resources = $this->get_list_by_conditions($conditions);
		$resources = array_column($resources, 'resource');
		
		return $resources;
	}
	
	/**
	 * 根据[搜索关键字]和[指定的模块集合]获取[相关语言项]列表
	 *
	 * @desc    【搜索关键字】+【模块名称 => 资源ID集合】+【语言标识】+【搜索字段】 => 相关语言项
	 * 			使用 group_start/group_end 特性构造复杂查询条件，去查询数据。
	 * 			For example, a SQL Statement Maybe like this:
				SELECT *
				FROM `language`
				WHERE `language` = 'english'
				AND `field_name` IN('name')
				AND `field_value` LIKE '%segwa%' ESCAPE '!'
				AND ( 
				       (`module` = 'merchant' AND `resource` IN('106', '108', -1)) 
				    OR (`module` = 'touroute' AND `resource` IN('45', '47', '60', -1))
				);
	 * @author  Jason
	 * @date	2017年5月27日 下午2:15:00
	 * @date	2017年5月27日 下午2:52:06
	 * @TODONE	maybe a func for liblang, DONE!
	 *
	 * @param string $keyword		关键字
	 * @param string $module		一个模型名，指定搜索的是什么	eg: 'merchant'
	 * @param array  $module_resources_pairs	关联数组：模型名 ==对应着=> 其ID列表。注意：!!ID列表不能为空数组!!！
	 * 								eg: [
												'merchant' => [45, 46, 47, -1],
												'touroute' => [-1],
										];
	 * @param string $language		语言标识
	 * @param array  $by_fields		探索的字段列表, 默认为 ['name']
	 *
	 * @return  array	数据数组
	 */
	public function get_list_for_search_in_multi_module($keyword, $module_resources_pairs, $language, $by_fields = ['name'])
	{
// 		$idsm[] = -1;
// 		$idst[] = -1;
// 		#
// 		$search_by = ['name'];
// 		$conditions = [
// 				['where', "language='$language'"],//
// 				['where_in', ['field_name', $search_by]],
// 				['like', ['field_value', $keyword/*, 'before'*/]],
// 				['group_start'],
// 				/*indent*/['group_start'],
// 				/*indent*//*indent*/['where', ['module', 'merchant']],
// 				/*indent*//*indent*/['where_in', ['resource', $idsm]],
// 				/*indent*/['group_end'],
// 				/*indent*/['or_group_start'],
// 				/*indent*//*indent*/['where', ['module', 'touroute']],
// 				/*indent*//*indent*/['where_in', ['resource', $idst]],
// 				/*indent*/['group_end'],
// 				['group_end'],
// 		];
// 		#
// 		$list = $this->lib_language->get_list_by_conditions($conditions);
// 		#
		
		// TO DO maybe a func for liblang
		$conditions = [
				['select', '*'],
				['where', "language='$language'"],//
				['where_in', ['field_name', $by_fields]],
				['like', ['field_value', $keyword/*, 'before'*/]],
		];
		$and_conditions = [];
		$firstTag = true;
		foreach ($module_resources_pairs as $module => $resources) {
			if ($firstTag) {
				$and_conditions[] = ['group_start'];
			} else {
				$and_conditions[] = ['or_group_start'];
			}
			$and_conditions[] = ['where', ['module', $module]];
			$and_conditions[] = ['where_in', ['resource', $resources]];
			$and_conditions[] = ['group_end'];
			$firstTag = false;
		}
		if (!empty($and_conditions)) {
			array_unshift($and_conditions, ['group_start']);
			array_push($and_conditions, ['group_end']);
		}
		
		$conditions = array_merge($conditions, $and_conditions);
		$list = $this->get_list_by_conditions($conditions);
		
		return $list;
	}
	
	
	
	public function get_list_by_conditions($conditions)
	{
		$this->CI->load->model('mod_language');
		$list = $this->CI->mod_language->select_instances_by_conditions($conditions);
		
		return $list;
	}
	
	/**
	 * 获取连接过的字段字符串
	 * 
	 * @desc    根据语言标识获取连接过的字段字符串, 适用于多个不同resource而field_name相同的字符串拼接
	 * 			eg: [country, city] => '中国 北京' / 'China Beijing' / ...
	 * @author  Jason
	 * @date    2017年5月23日 下午10:05:01
	 * 
	 * @param string $module		一个模型名，指定搜索的是什么	eg: 'area'
	 * @param array  $resources		非语言字段限定条件过滤之后的ID列表
	 * @param string $language		语言标识
	 * @param array  $by_field		探索的字段名称, 默认为 'name'
	 * //@param array  $by_fields		探索的字段列表, 默认为 ['name']
	 * 
	 * @return  string	returnDescription
	 */
	public function get_concat_values_string_by_language($module, $resources, $language, $by_field = 'name'/*$by_fields = ['name']*/)
	{
		$names = $this->get_list_by_conditions([
				['select', "resource,field_value"],
				['where', "module='$module' AND language='$language' AND field_name='$by_field'"],
				['where_in', ['resource', $resources]],
		]);
		$names = array_column($names, 'field_value', 'resource');
		
		$string = '';
		foreach ($resources as $key) {
			$string .= @$names[$key] . " ";
		}
		$string = trim($string);
		
		return $string;
	}
	
	
	/**
	 * 直接查询某模型的语言
	 *
	 */
	public function select_language($resource, $module, $language)
	{
		if (is_array($module)) {
			$model = $module[0];
			$mapper = !empty($module[1]) ? $module[1] : 'master';
		}
		else {
			// reflection
			$model = lcfirst(basename(str_replace('\\', '/', get_called_class() . '_model')));
			$model = $this->CI->$model;
			$mapper = 'master';
		}
		// var_dump($model ,$mapper);
		
		$module = $model->get_multi_language_info('module', $mapper);
		$fields = $model->get_multi_language_info('fields', $mapper);
		// var_dump($module ,$fields);
		
		$this->CI->load->model('mod_language');
		$record = $this->CI->mod_language->select_record($module, $resource, $language);
		$language_data = $this->get_item_single_language_info($record, $language);
		$data['values'] = array_merge(array_fill_keys($fields, ''), @(array) $language_data['values']);
		
		return $data;
	}
	
	/**
	 * 添加语言
	 * 
	 * @desc   写一行 insert_record
	 * @param  number $resource 资源ID
	 * @param  [type] $data     [description]
	 * @param  [type] $module   [description]
	 * @param  string $language [description]
	 * @return [type]           [description]
	 */
	public function create_language($resource, $data, $module, $language)
	{
		if (is_array($module)) {
			$model = $module[0];
			$mapper = !empty($module[1]) ? $module[1] : 'master';
		}
		else {
			// reflection
			$model = lcfirst(basename(str_replace('\\', '/', get_called_class() . '_model')));
			$model = $this->CI->$model;
			$mapper = 'master';
		}
		// var_dump($model ,$mapper);
		
		$module = $model->get_multi_language_info('module', $mapper);
		$fields = $model->get_multi_language_info('fields', $mapper);
		// var_dump($module ,$fields);
		
		$this->CI->load->model('mod_language');
		$pairs = Mod_language::make_pairs($data, $fields) ;
		// OR $this->CI->mod_language->make_pairs($data, $fields);
		$this->CI->mod_language->insert_record($module, $resource, $language, $pairs);
	}
	
	/**
	 * 更新语言
	 *
	 * @desc   更新一行 update_record
	 * @param  number $resource 资源ID
	 * @param  [type] $data     [description]
	 * @param  [type] $module   [description]
	 * @param  string $language [description]
	 * @return [type]           [description]
	 */
	public function update_language($resource, $data, $module, $language)
	{
		if (is_array($module)) {
			$model = $module[0];
			$mapper = !empty($module[1]) ? $module[1] : 'master';
		}
		else {
			// reflection
			$model = lcfirst(basename(str_replace('\\', '/', get_called_class() . '_model')));
			$model = $this->CI->$model;
			$mapper = 'master';
		}
		// var_dump($model ,$mapper);
		
		$module = $model->get_multi_language_info('module', $mapper);
		$fields = $model->get_multi_language_info('fields', $mapper);
		// var_dump($module ,$fields);
		
		$this->CI->load->model('mod_language');
		$pairs = Mod_language::make_pairs($data, $fields) ;
		// OR $this->CI->mod_language->make_pairs($data, $fields);
		$this->CI->mod_language->update_record($module, $resource, $language, $pairs);
	}
	
	/**
	 * 按资源删除语言
	 *
	 * @desc   删除一个资源
	 * @param  string $module   模块名称：字符串有限集（枚举）
	 * @param  number $resource 资源ID
	 * @return [type]           [description]
	 */
	public function delete_language($module, $resource)
	{
		if (!is_string($module)) {
			return false;
		}
		if (empty($resource)) {
			return false;
		}
		
		$conditions = [
				['where', "`resource`='$resource' AND `module`='$module'"],
		];
		$this->CI->load->model('mod_language');
		$this->CI->mod_language->delete_instances_by_conditions($conditions);
	}
}